package com.ruoyi.framework.config.sms;

import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.service.ISysUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

/**
 * 验证码登录
 * 因为使用spring security，所以需要自定义如下几个类跟security集成
 * AuthenticationToken
 * AuthenticationProvider
 * UserDetailsService
 * 最后在security配置类中设置provider
 * @author 天天向上 （john.yi@qq.com）
 * @date 2020/9/15.
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class SmsLoginService {
    private final ISysUserService sysUserService;
    private final StringRedisTemplate stringRedisTemplate;
    private final ValidCodeConfig validCodeConfig;
    private final TokenService tokenService;
    private final AuthenticationManager authenticationManager;

    public boolean isExists(String phoneNumber) {
        return sysUserService.selectUserByPhone(phoneNumber) != null;
    }

    public String login(String phoneNumber, String validCode) {
        String key = validCodeConfig.getValidCodeKeyPrefix() + ":" + phoneNumber;
        if (!validCode.equals(stringRedisTemplate.opsForValue().get(key))) {
            throw new BadCredentialsException("验证码错误");
        }
        SysUser sysUser = sysUserService.selectUserByPhone(phoneNumber);
        if (sysUser == null) {
            throw new UsernameNotFoundException("手机号码不存在");
        }
        return createToken(sysUser.getPhonenumber());
    }

    public String createToken(String username) {
        // 用户验证
        Authentication authentication = null;
        try {
            // 该方法会去调用SmsUserDetailsService.loadUserByUsername
            authentication = authenticationManager
                    .authenticate(new SmsCodeAuthenticationToken(username));
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            } else {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
                throw new CustomException(e.getMessage());
            }
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        // 生成token
        return tokenService.createToken(loginUser);
    }
}
